/*
 * Copyright (c) 2018, apexes.net. All rights reserved.
 *
 *         http://www.apexes.net
 *
 */
package net.apexes.vertx;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.eventbus.impl.clustered.ClusteredMessage;
import io.vertx.core.eventbus.impl.clustered.ClusteredMessages;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.core.net.impl.ServerID;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;

/**
 * @author <a href="mailto:hedyn@foxmail.com">HeDYn</a>
 */
public final class VertxGuices {
    private VertxGuices() {}

    private static final Logger LOG = LoggerFactory.getLogger(VertxGuices.class);
    
    public static final String DATE_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS";

    public static void configureJsonMapper(Module module) {
        Json.mapper.registerModule(module);
        Json.prettyMapper.registerModule(module);
    }

    public static void configureDefaultJsonMapper() {
        configureDefaultJsonMapper(Json.mapper);
        configureDefaultJsonMapper(Json.prettyMapper);
    }

    public static void configureDefaultJsonMapper(ObjectMapper mapper) {
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapper.setDateFormat(new SimpleDateFormat(DATE_PATTERN));
        mapper.setVisibility(mapper.getVisibilityChecker()
                .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withIsGetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withFieldVisibility(JsonAutoDetect.Visibility.ANY));
    }

    public static VertxClustered clustered(VertxOptions vertxOptions) {
        return clustered(vertxOptions, null, null);
    }

    public static VertxClustered clustered(VertxOptions vertxOptions, ClusteredMessageLogger logger) {
        return clustered(vertxOptions, null, logger);
    }

    public static VertxClustered clustered(VertxOptions vertxOptions, GuiceVerticleFactory factory) {
        return clustered(vertxOptions, factory, null);
    }

    public static VertxClustered clustered(VertxOptions vertxOptions, GuiceVerticleFactory factory, ClusteredMessageLogger logger) {
        CompletableFuture<VertxClustered> future = new CompletableFuture<>();
        Vertx.clusteredVertx(vertxOptions, res -> {
            if (res.succeeded()) {
                Vertx vertx = res.result();
                future.complete(new VertxClustered(vertx, factory, logger));
            } else {
                future.completeExceptionally(res.cause());
            }
        });
        try {
            return future.get();
        } catch (Exception e) {
            LOG.error("clustered error!", e);
            return null;
        }
    }

    public static ServerID getSender(ClusteredMessage message) {
        return ClusteredMessages.getSender(message);
    }

    public static JsonObject jsonResource(String name) {
        InputStream is = VertxGuices.class.getResourceAsStream(name);
        StringBuilder sb = new StringBuilder();
        String line;
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            return new JsonObject(sb.toString());
        } catch (IOException e) {
            LOG.error(e.getMessage(), e);
            return new JsonObject();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                LOG.error(e.getMessage(), e);
            }
        }
    }

    public static Properties propertiesResource(String name) {
        Properties properties = new Properties();
        InputStream is = VertxGuices.class.getResourceAsStream(name);
        try {
            properties.load(is);
        } catch (IOException e) {
            LOG.error(e.getMessage(), e);
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                LOG.error(e.getMessage(), e);
            }
        }
        return properties;
    }

    public static List<String> getAsStringOrList(JsonObject json, String key) {
        Object value = json.getValue(key);
        if (value == null) {
            return null;
        } else {
            if (value instanceof String) {
                return asList((String) value);
            } else if (value instanceof JsonArray) {
                return (List<String>) ((JsonArray) value).getList();
            } else {
                throw new IllegalArgumentException("invalid attachment type");
            }
        }
    }

    static <T> List<T> asList(T element) {
        return Collections.singletonList(element);
    }
    
}
